home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / mus / play / tracker_4_31.lzh / tracker / Amiga / server / sound.c < prev    next >
C/C++ Source or Header  |  1995-02-13  |  11KB  |  383 lines

  1. /* amiga/server/sound.c */
  2.  
  3. /* internal operations for the sound server itself */
  4.  
  5. /* $Id: sound.c,v 1.13 1995/02/13 22:08:26 Espie Exp espie $
  6.  * $Log: sound.c,v $
  7.  * Revision 1.13  1995/02/13  22:08:26  Espie
  8.  * No boolean. Changed include path.
  9.  *
  10.  * Revision 1.12  1994/01/08  20:26:45  Espie
  11.  * Added pause gadget.
  12.  *
  13.  * Revision 1.11  1994/01/07  15:12:26  Espie
  14.  * *** empty log message ***
  15.  *
  16.  * Revision 1.10  1994/01/07  01:01:49  Espie
  17.  * Id.
  18.  *
  19.  * Revision 1.9  1994/01/05  16:11:43  Espie
  20.  * Made TYPE_xxxSYNC explicit.
  21.  *
  22.  * Revision 1.8  1994/01/05  14:56:02  Espie
  23.  * *** empty log message ***
  24.  *
  25.  * Revision 1.7  1994/01/05  04:35:23  Espie
  26.  * Found spurious bug: I had to track through the various
  27.  * possibilities of CMD_WRITE to finally realize I was losing my
  28.  * messages... So when the queue was empty, I could not allocate
  29.  * any channel...
  30.  * Needed external program capability back in order though.
  31.  * Problem was coming from data faronly, which is very incompatible
  32.  * with printf.
  33.  *
  34.  * Note that now, we only care about reallocating channels when we're
  35.  * doing a CMD_WRITE. doing it for ADCMD_PERVOL or CMD_FLUSH is pointless
  36.  * since our old data have been completely forgotten in between...
  37.  *
  38.  * Some tests and masking are probably unnecessary. On the other hand, the
  39.  * error code MUST be checked correctly. Maybe I'll try and make the
  40.  * CMD_WRITE part clearer.
  41.  *
  42.  * Revision 1.6  1994/01/05  02:03:14  Espie
  43.  * Mostly correct check for losing audio channels.
  44.  *
  45.  * Revision 1.5  1994/01/04  22:05:35  Espie
  46.  * Cosmetic changes, mostly.
  47.  *
  48.  * Revision 1.4  1994/01/04  20:46:23  Espie
  49.  * Plainly working version with all checks...
  50.  *
  51.  * Revision 1.3  1994/01/04  20:33:20  Espie
  52.  * Mostly working version
  53.  *
  54.  * Revision 1.2  1994/01/04  19:13:21  Espie
  55.  * Corrected most of the audio allocation/free muck-up.
  56.  *
  57.  * Revision 1.1  1994/01/04  15:45:37  Espie
  58.  * Initial revision
  59.  *
  60.  */
  61.  
  62. #include <hardware/cia.h>
  63. #include <hardware/intbits.h>
  64. #include <hardware/dmabits.h>
  65. #include <exec/nodes.h>
  66. #include <exec/memory.h>
  67. #include <devices/audio.h>
  68. #include <proto/exec.h>
  69. #include <stddef.h>
  70.  
  71. #include <stdio.h>
  72.  
  73.  
  74. #include "defs.h"
  75. #include "amiga/amiga.h"
  76. #include "amiga/server/server.h"
  77.  
  78. ID("$Id: sound.c,v 1.13 1995/02/13 22:08:26 Espie Exp espie $")
  79. extern volatile struct CIA __far ciaa;
  80.  
  81. UBYTE saved_filter, current_filter;
  82.  
  83. /* we allow for lots more audio requests than we need */
  84. #define QUEUE_LENGTH 50
  85.  
  86.  
  87. LOCAL struct ext_audio
  88.    {
  89.    struct MinNode node;
  90.    struct IOAudio request;
  91.    }
  92. /* for sending immediate commands */
  93.  *immediate = 0;
  94. /* the specific request that gets used for closing/opening */
  95. struct IOAudio *req = 0;
  96.  
  97. /* the audio queue */
  98. struct MinList queue;
  99.  
  100. /* keep track of progress */
  101. struct MinList pending;
  102.  
  103. LOCAL struct MsgPort *aport = 0;
  104. /* in order to clean up afterwards: */
  105. LOCAL int audio_opened = FALSE;
  106.  
  107. void send_immediate(ULONG command, int mask);
  108. LOCAL void get_requests(void);
  109.  
  110. /* mask for allocation */
  111. LOCAL UBYTE whichchannel[1];
  112. /* mask of owned channels */
  113. LOCAL UBYTE owned;
  114.  
  115. /* allocate_channels(mask): sends a request to the audio.device for
  116.  * the channels described by mask
  117.  */
  118. LOCAL void allocate_channels(UBYTE mask)
  119.    { 
  120.    whichchannel[0] = mask & ~owned;
  121.    req->ioa_Request.io_Command = ADCMD_ALLOCATE;
  122.    req->ioa_Data = whichchannel;
  123.    req->ioa_Length = sizeof(whichchannel);
  124.    req->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
  125.    BeginIO(req);
  126.    WaitIO(req);
  127.    if (!req->ioa_Request.io_Error)     /* update owned channels mask */
  128.       {
  129.       owned |= (int)req->ioa_Request.io_Unit;
  130. #ifdef EXTERNAL
  131.       printf("Allocated: %d (%d) = %d\n", (int)mask, (int)req->ioa_Request.io_Unit, (int)owned);
  132.       fflush(stdout);
  133. #endif
  134.       }
  135. #ifdef EXTERNAL
  136.    else
  137.       printf("Failed: %d (%d) = %d\n", req->ioa_Request.io_Error, mask, owned);
  138. #endif
  139.    ciaa.ciapra = (ciaa.ciapra & ~ CIAF_LED) | current_filter;
  140.    }
  141.  
  142. /* free_channels(): give back all channels.
  143.  */ 
  144. LOCAL void free_channels(void)
  145.    {
  146.    if (req->ioa_AllocKey)
  147.       {
  148.       req->ioa_Request.io_Command = ADCMD_FREE;
  149.       req->ioa_Request.io_Unit = owned;
  150.       BeginIO(req);
  151.       WaitIO(req);
  152. #ifdef EXTERNAL
  153.       printf("Freed !\n");
  154.       fflush(stdout);
  155. #endif
  156.       owned = 0;
  157.       }
  158.    }
  159.  
  160. LOCAL struct ext_audio *create_request(void)
  161.    {
  162.    struct ext_audio *new;
  163.          /* CHECK: no test for failed allocation */
  164.    new = AllocMem(sizeof(struct ext_audio), MEMF_CLEAR|MEMF_PUBLIC);
  165.    if (req && new)
  166.       new->request = *req;
  167.    return new;
  168.    }
  169.  
  170. /* actual = create_queue(n): creates a queue of n audio requests,
  171.  *    returns the actual number
  172.  */   
  173. LOCAL int create_queue(int n)
  174.    {
  175.    int i;
  176.    struct ext_audio *new;
  177.  
  178.    for (i = 0; i < n; i++)
  179.       {
  180.       new = create_request();
  181.       if (!new)
  182.          return i;
  183.       AddTail(&queue, new);
  184.       }  
  185.    return i;
  186.    }
  187.  
  188. /* get back available requests */
  189. LOCAL void get_requests(void)
  190.    {
  191.    struct IOAudio *back;
  192.  
  193.    while(back = GetMsg(aport))
  194.       {
  195.       struct ext_audio *full;
  196.       full = (struct ext_audio *)
  197.          (((UBYTE *)back) - offsetof(struct ext_audio, request));
  198.       Remove(full);           /* no longer pending */
  199.       AddTail(&queue, full);  /* ... and available */
  200.       }
  201.    }
  202.  
  203. /* send immediate command.
  204.  * WARNING: only use send_immediate with commands which
  205.  * are GUARANTEED to be synchronous if IOF_QUICK is set
  206.  */
  207. void send_immediate(ULONG command, int mask)
  208.    {
  209.    immediate->request.ioa_Request.io_Command = command;
  210.    immediate->request.ioa_Request.io_Flags = IOF_QUICK;
  211.    immediate->request.ioa_Request.io_Unit = (void *)(mask & owned);
  212.    immediate->request.ioa_AllocKey = req->ioa_AllocKey;
  213.    BeginIO(&immediate->request);
  214.    return;     
  215.    }
  216.  
  217. void reset_audio(void)
  218.    {
  219.    send_immediate(CMD_FLUSH, 15);
  220.    get_requests();
  221.    free_channels();
  222.    }
  223.  
  224. /* obtain_audio(): allocate all the structures we will need to
  225.  * play with the audio device
  226.  */ 
  227. LOCAL void obtain_audio(void)
  228.    {
  229.    BYTE fail;
  230.    
  231.    aport = CreateMsgPort();
  232.    if (!aport)
  233.       return;
  234.    req = CreateIORequest(aport, sizeof(struct IOAudio));
  235.    if (!req)
  236.       return;
  237.    req->ioa_AllocKey = 0;
  238.    req->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  239.       /* Note that OpenDevice returns 0 on success
  240.        */
  241.    fail = OpenDevice("audio.device", 0L, (struct IORequest *)req, 0L);
  242.    if (!fail)
  243.       audio_opened = TRUE;
  244.    }
  245.  
  246. struct MsgPort *start_audio(void)
  247.    {
  248.    NewList(&queue);     /* initialize these now for correct cleanup */
  249.    NewList(&pending);
  250.  
  251.    owned = 0;           /* we own no channel right now */
  252.    obtain_audio();
  253.    if (!audio_opened || create_queue(QUEUE_LENGTH) < QUEUE_LENGTH)
  254.       return 0;
  255.    immediate = RemHead(&queue);
  256.    saved_filter = ciaa.ciapra & CIAF_LED;
  257.    current_filter = CIAF_LED;
  258.    return aport;  
  259.    }  
  260.  
  261. void end_audio()
  262.    {
  263.    struct ext_audio *sweep, *next;
  264.  
  265.    if (immediate)       /* get immediate back in queue for freeing it */
  266.       AddTail(&queue, immediate);
  267.    if (req)
  268.       free_channels();
  269.    get_requests();
  270.       /* REMOVE ALL REQUESTS FROM THE PENDING LIST */
  271.    SCANLIST(sweep, next, &pending, struct ext_audio *)
  272.       {
  273.       AbortIO(&sweep->request);
  274.       WaitIO(&sweep->request);
  275.       }
  276.       /* Now we can close safely */
  277.    if (audio_opened)
  278.       CloseDevice((struct IORequest *)req);
  279.    if (req)
  280.       DeleteIORequest(req);
  281.    if (aport)
  282.       DeletePort(aport);
  283.  
  284.    SCANLIST(sweep, next, &queue, struct ext_audio *)
  285.       FreeMem(sweep, sizeof(struct ext_audio));
  286.    ciaa.ciapra = (ciaa.ciapra & ~CIAF_LED) | saved_filter;
  287.    }
  288.  
  289.  
  290. /* Perform musical events pertaining to the current time */
  291. void do_events(struct List *e)
  292.    {
  293.    struct ext_message *msg, *msg2;
  294.    
  295.    while (msg = RemHead(e))
  296.       {
  297.       switch (msg->type)
  298.          {
  299.       case TYPE_WAIT:         /* next time to wait for: finished */
  300.          AddHead(e, msg);
  301.          return;
  302.       case TYPE_FLUSH_CHANNEL:
  303.          send_immediate(CMD_FLUSH, msg->data.info.channel_mask);
  304.          break;
  305.       case TYPE_SETUP:        /* setup is a two message command */
  306.          msg2 = RemHead(e);
  307.          
  308.          if (msg2)
  309.             {
  310.             struct ext_audio *new;
  311.             
  312.             new = RemHead(&queue);
  313.             if (new)
  314.                {
  315.                new->request.ioa_Request.io_Command = CMD_WRITE;
  316.                if (msg2->data.info.pitch)
  317.                   {
  318.                   new->request.ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK;
  319.                   new->request.ioa_Period = msg2->data.info.pitch;
  320.                   new->request.ioa_Volume = msg2->data.info.volume;
  321.                   }
  322.                else
  323.                   new->request.ioa_Request.io_Flags = IOF_QUICK;
  324.                if ((owned & msg2->data.info.channel_mask) == 0)
  325.                   allocate_channels(msg2->data.info.channel_mask);
  326.                new->request.ioa_Request.io_Unit = msg2->data.info.channel_mask & owned;
  327.                new->request.ioa_Cycles = msg2->data.info.cycle;
  328.                new->request.ioa_Data = msg->data.sample.start;
  329.                new->request.ioa_Length= msg->data.sample.length;
  330.                new->request.ioa_AllocKey = req->ioa_AllocKey;
  331.                if (new->request.ioa_Request.io_Unit)
  332.                   {
  333.                   BeginIO(&new->request);
  334.                   if (new->request.ioa_Request.io_Flags & IOF_QUICK)
  335.                      {
  336.                      AddTail(&queue, new);
  337.                      if (new->request.ioa_Request.io_Error)
  338.                         {
  339.                         owned &=~ msg2->data.info.channel_mask;
  340. #ifdef EXTERNAL
  341.                         printf("Lost: %d (%d) = %d\n", new->request.ioa_Request.io_Error, msg2->data.info.channel_mask, owned);
  342.                         fflush(stdout);
  343. #endif
  344.                         }
  345.                      }
  346.                   else
  347.                      AddTail(&pending, new);
  348.                   }
  349.                else
  350.                   AddTail(&queue, new);
  351.                }
  352. #ifdef EXTERNAL
  353.             else
  354.                printf("No new\n");
  355. #endif
  356.             ReplyMsg(msg2);
  357.             }        
  358.          break;
  359.       case TYPE_CHANGE:
  360.          immediate->request.ioa_Period = msg->data.info.pitch;    
  361.          immediate->request.ioa_Volume = msg->data.info.volume;
  362.          send_immediate(ADCMD_PERVOL, msg->data.info.channel_mask);
  363.          break;
  364.       case TYPE_COMM:
  365.       case TYPE_SYNC:
  366.       case TYPE_SYNC_DO:
  367.          /* nothing to do there */
  368.          break;
  369.       default:
  370.          /* not implemented yet */
  371.          break;
  372.          }
  373.       ReplyMsg(msg);
  374.       get_requests();
  375.       }
  376.    }
  377.  
  378.    
  379. void handle_audio(struct List *l, int signaled)
  380.    {
  381.    get_requests();
  382.    }
  383.